package com.wispx.gateway.config.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wispx.gateway.config.config.ConfigCenter;
import com.wispx.gateway.config.config.lib.NacosConfig;
import com.wispx.gateway.config.pojo.RouteDefinition;
import com.wispx.gateway.config.service.ConfigCenterProcessor;
import com.wispx.gateway.config.service.RouteChangeListener;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Nacos 配置中心
 */
@Slf4j
public class NacosConfigCenter implements ConfigCenterProcessor {

    /**
     * 配置中心
     */
    private ConfigCenter configCenter;

    /**
     * Nacos SDK 提供的 Client
     */
    private ConfigService configService;

    /**
     * 自己定义的配置变更监听器
     */
    private RouteChangeListener listener;

    /**
     * 是否初始化
     */
    private AtomicBoolean init = new AtomicBoolean(false);

    @Override
    @SneakyThrows(NacosException.class)
    public void init(ConfigCenter configCenter) {
        if (!configCenter.isEnable() || !init.compareAndSet(false, true)) {
            return;
        }
        this.configCenter = configCenter;
        this.configService = NacosFactory.createConfigService(buildProperty(configCenter));
    }

    @Override
    @SneakyThrows(Exception.class)
    public void subscribeConfigChange(RouteChangeListener listener) {
        if (!configCenter.isEnable() || !init.get()) {
            return;
        }
        this.listener = listener;

        NacosConfig nacos = configCenter.getNacos();
        // 从 Nacos 获取配置文件，dataId + group 确定唯一的配置文件
        String configJSON = configService.getConfig(nacos.getDataId(), nacos.getGroup(), nacos.getTimeout());
        /* configJson:
         * Nacos服务端配置中心格式为 JSON，如下：
         * {
         *     "routes": [
         *         {
         *             "id": "user-service-route",
         *             "serviceName": "user-service",
         *             "uri": "/api/user/**"
         *         }
         *     ]
         * }
         */
        log.info("config from nacos:{}", configJSON);
        List<RouteDefinition> routes = JSON.parseObject(configJSON).getJSONArray("routes").toJavaList(RouteDefinition.class);
        listener.routeOnChange(routes); // 首次订阅，手动触发一次
        configService.addListener(nacos.getDataId(), nacos.getGroup(), new NacosConfigCenterListener());
    }

    private Properties buildProperty(ConfigCenter configCenter) {
        Properties properties = new Properties();
        properties.put("serverAddr", configCenter.getAddress());
        ObjectMapper mapper = new ObjectMapper();
        Map map = mapper.convertValue(configCenter.getNacos(), Map.class);
        if (map != null && !map.isEmpty()) {
            properties.putAll(map);
        }
        return properties;
    }

    private class NacosConfigCenterListener implements Listener {

        @Override
        public Executor getExecutor() {
            return null;
        }

        @Override
        public void receiveConfigInfo(String configInfo) {
            // 处理配置更新
            log.info("nacos config change to:{}", configInfo);
            List<RouteDefinition> changedRoutes = JSON.parseObject(configInfo).getJSONArray("routes").toJavaList(RouteDefinition.class);
            listener.routeOnChange(changedRoutes);
        }
    }

}
